/**
 * #info
 *
 *@author   wuwg
 *@createTime   2018/03/20
 *@updateTime   2018/04/17
 *@description  cascader  component   级联动组件
 */

/**
 * #item
 *
 * @type   aty-cascader
 * @cn     级联选择
 * @nameprop   label
 * @menu        表单
 * @stPlugin    true
 * @stContainer false
 * @children    []
 * @mixins      [./components/components/form/form-item/form-item.js]
 */
import config from '../../../config/config.js'

// components
import Drop from '../select/dropdown/index.vue'
import Caspanel from './caspanel/index.vue'
// directives
import clickoutside from '../../../directives/clickoutside'
import TransferDom from '../../../directives/transfer-dom'
// mixins
import Locale from '../../../mixins/locale.js'
import formItem from '../form-item/form-item.js'
// prefix
const componentName = config.prefix + '-cascader'
// module
export default {
  name: componentName,
  mixins: [formItem, Locale],
  components: { Drop, Caspanel },
  directives: { clickoutside, TransferDom },
  props: {
    /**
     * #property
     *
     * @name    elementId
     * @cn      input id
     * @group   基本属性
     * @type    String
     * @description HTML label元素的for属性 input元素的id属性
     */
    elementId: {
      type: String
    },
    /**
     * #property
     *
     * @name    value
     * @cn      值
     * @group   基本属性
     * @type    Array
     * @bind   must
     * @description 组件的值
     */
    value: {
      type: Array,
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name    data
     * @cn      数据列表
     * @group   数据
     * @type    Array
     * @bind    must
     * @description  可选项的数据源，格式参照示例说明
     */
    data: {
      type: Array,
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name    clearable
     * @cn      是否支持清除
     * @group   控制
     * @type    boolean
     * @bind    must
     * @value   true
     * @description 该输入框是否是否支持清除
     */
    clearable: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    trigger
     * @cn      触发事件
     * @group   基本属性
     * @type    list
     * @options [click, hover]
     * @value    click
     * @description 次级菜单展开方式，取值为 ['click', 'hover']中的其中一个
     */
    trigger: {
      validator (value) {
        return Artery.isOneOf(value, ['click', 'hover'])
      },
      default: 'click'
    },
    /**
     * #property
     *
     * @name    changeOnSelect
     * @cn      及时改变
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 当此项为 true 时，点选每级菜单选项值都会发生变化
     */
    changeOnSelect: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    renderFormat
     * @cn      选择后展示的函数，用于自定义显示格式
     * @group   基本属性
     * @type    function
     * @bind    must
     * @description   选择后展示的函数，用于自定义显示格式，例如：function(label){return label.join(' / ')}
     */
    renderFormat: {
      type: Function,
      default (label) {
        return label.join(' / ')
      }
    },
    /**
     * #property
     *
     * @name    loadData
     * @cn      动态加载数据的方法
     * @group   数据
     * @type    function
     * @bind    must
     * @description   动态加载数据的方法，设置
     */
    loadData: {
      type: Function
    },
    /**
     * #property
     *
     * @name    transfer
     * @cn      是否将弹层放置于 body 内
     * @group   控制
     * @type    boolean
     * @value   false
     * @description  是否将弹层放置于 body 内，
     *              在 Tabs、带有 fixed 的 Table 列内使用时，建议添加此属性，它将不受父级样式影响，从而达到更好的效果
     */
    transfer: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      prefixCls: componentName,
      visible: false,
      selected: [],
      tmpSelected: [],
      validDataStr: ''
    }
  },
  watch: {
    visible (val) {
      if (val) {
        if (this.selected.length) {
          this.updateSelected()
        }
        if (this.transfer) {
          this.$refs.drop.update()
        }
        this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
      } else {
        if (this.transfer) {
          this.$refs.drop.destroy()
        }
      }
      /**
       * #event
       *
       * @name    visible-change
       * @param   value  当前visible的值
       * @body
       * @description 展开和关闭弹窗时触发
       */
      this.$emit('visible-change', val)
    },
    value (val) {
      if (!val.length) {
        this.selected = []
      }
      this.updateSelected(true)
    },
    data: {
      deep: true,
      handler () {
        const validDataStr = JSON.stringify(this.getValidData(this.data))
        if (validDataStr !== this.validDataStr) {
          this.validDataStr = validDataStr
          this.$nextTick(() => this.updateSelected(false, this.changeOnSelect))
        }
      }
    }
  },
  computed: {
    inputListeners: function () {
      const _this = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 从父级添加所有的监听器
        this.$listeners,
        // 自定义监听器，或覆写一些监听器的行为
        {
          click: function (event) {
            _this.$emit('click', event)
            _this.toggleOpen()
          },
          blur: function (event) {
            _this.$emit('blur', event)
            _this.validate()
          }
        }
      )
    },
    inputAttrs: function () {
      return Object.assign({},
        // 默认属性
        {
          type: 'text',
          autocomplete: 'off',
          readonly: true,
          placeholder: this.t('i.select.placeholder')
        },
        this.$attrs
      )
    },
    isDisabled () {
      return this.inputAttrs.disabled !== undefined && this.inputAttrs.disabled !== false
    },
    showClear () {
      return this.selected.length && this.clearable && !this.isDisabled
    },
    displayValue () {
      const label = []
      for (let i = 0; i < this.selected.length; i++) {
        label.push(this.selected[i].label)
      }
      return this.renderFormat(label, this.selected)
    },
    wrapClasses () {
      return [
        `${componentName}-wrapper`,
        {
          [`${componentName}-visible`]: this.visible
        }
      ].concat(this.formItemClasses)
    },
    wrapStyles () {
      return this.formItemStyles
    },
    inputClasses () {
      return [
        `${componentName}`,
        `${componentName}-hasicon`,
        {
          [`${componentName}-disabled`]: this.isDisabled
        }
      ]
    },
    inputStyles () {
      const style = {}
      return style
    },
    clearClasses () {
      return [
        config.prefix + '-icon',
        config.prefix + '-icon-ios-close',
        componentName + '-icon',
        componentName + '-icon-clear',
        { show: this.selected.length }
      ]
    },
    arrowClasses () {
      return [
        config.prefix + '-icon',
        config.prefix + '-icon-arrow-down-b',
        componentName + '-icon',
        componentName + '-icon-arrow',
        { hide: this.showClear && this.selected.length }
      ]
    }
  },
  methods: {
    // 重置为初始值
    reset () {
      this.selected = this.tmpSelected = this._originalSelected
      this.$emit('input', this._originalValue)
      this.$emit('change')
    },
    handleClear (event) {
      if (this.isDisabled) {
        return false
      }
      this.selected = this.tmpSelected = []
      this.$emit('input', [], event)
      this.$emit('change', event)
      this.handleClose()
      this.broadcast('Caspanel', 'clear')
    },
    handleClose () {
      this.visible = false
    },
    toggleOpen () {
      if (this.isDisabled) {
        return false
      }
      if (this.visible) {
        this.handleClose()
      } else {
        this.visible = true
        if (!this.selected.length) {
          this.broadcast('Caspanel', 'clear')
        }
      }
    },
    // 子组件调用
    updateResult (result) {
      this.tmpSelected = result
    },
    updateSelected (init = false, changeOnSelectDataChange = false) {
      // #2793 changeOnSelectDataChange used for changeOnSelect when data changed and set value
      if (this.changeOnSelect || init || changeOnSelectDataChange) {
        this.broadcast('Caspanel', 'find-selected', {
          value: this.value
        })
      }
    },
    // 排除 loading 后的 data，避免重复触发 updateSelect
    getValidData (data) {
      function deleteData (item) {
        const newItem = Object.assign({}, item)
        if ('loading' in newItem) {
          delete newItem.loading
        }
        if ('__value' in newItem) {
          delete newItem.__value
        }
        if ('__label' in newItem) {
          delete newItem.newItem
        }
        if ('children' in newItem && newItem.children.length) {
          newItem.children = newItem.children.map(i => deleteData(i))
        }
        return newItem
      }

      return data.map(item => deleteData(item))
    }
  },
  created () {
    this.validDataStr = JSON.stringify(this.getValidData(this.data))
    this.$on('result-change', (params) => {
      /*
       *   console.log(params)
       * lastValue: is click the final val
       * fromInit: is this emit from update value
       */
      const lastValue = params.lastValue
      const changeOnSelect = params.changeOnSelect
      const fromInit = params.fromInit
      if (lastValue || changeOnSelect) {
        this.selected = this.tmpSelected
        const newVal = []
        this.selected.forEach((item) => {
          newVal.push(item.value)
        })
        this.validate()
        if (fromInit) {
          this._originalSelected = Artery.deepCopy(this.selected)
        } else {
          this.$emit('input', newVal)
          /**
           * #event
           *
           * @name    change
           * @cn      值改变
           * @param   event    当前事件的event对象，可能没有
           * @body
           * @description 值改变时触发
           */
          this.$emit('change')
        }
      }
      if (lastValue && !fromInit) {
        this.handleClose()
      }
    })
    // 保存初始值，用于reset
    this._originalValue = Artery.deepCopy(this.value)
  },
  mounted () {
    this.updateSelected(true)
  }
}
